package com.lcx.util;

import javafx.application.Platform;
import javafx.scene.web.WebEngine;

import java.lang.reflect.Method;

public class JsTemplateUtil {

    /**
     * 异步执行对象
     */
    public static final String exector="_exector";

    /**
     * 同步执行对象
     */
    public static final String syncExector="_syncExector";

    /**
     * js缓存对象
     */
    public static final String wCache = "_xcache";

    /**
     * 执行完成回掉函数
     */
    public static final String completeCall = "_runSucc";


    public static final String generateFuncId = "_generateFuncId";

    /**
     * 异步方法计数器
     */
    public static final String methodCount = "_methodCount";

    /**
     * java调用js代码的代理方法名
     */
    public static final String proxyJsExtorMethodName="proxyJsExector";


    /**
     * 生成一个同步js代理方法，代理指定的类的方法。
     * @param objName
     * @param m
     * @return
     */
    public static final String generateSyncProxyMethod(String objName,Method m){
        StringBuilder jsScript = new StringBuilder();
        Class<?> params[] = m.getParameterTypes();
        jsScript.append("var_.").append(m.getName())
                .append("=function ").append("(");
        if(params!=null && params.length>0){
            for(int i=0;i<params.length;i++){
                if(i>0) jsScript.append(",");
                jsScript.append(" var").append(i);
            }
        }
        jsScript.append("){");
        if(params!=null && params.length>0){
            jsScript.append("var args=[];")
                    .append("for(var i=0;i<").append(params.length).append(";i++){")
                    .append("args[i]=arguments[i];")
                    .append("}");
        }
        jsScript.append("var result = ")
                .append(syncExector)
                .append(".exec(")
                .append("'")
                .append(objName)
                .append("','")
                .append(m.getName())
                .append("'");
        if(params!=null && params.length>0){
            jsScript.append(",JSON.stringify(args)");
        }else{
            jsScript.append(",null");
        }
        jsScript.append(");")
                .append("return result?JSON.parse(result):result;")
                .append("};");


        return jsScript.toString();
    }

    /**
     * 生成一个异步具备回调的js代理方法，代理指定类的指定方法
     * @param objName
     * @param m
     * @return
     */
    public final static String generateProxyMethod(String objName,Method m){
        StringBuilder jsScript = new StringBuilder();
        Class<?> params[] = m.getParameterTypes();
        jsScript.append("var_.").append(m.getName())
                .append("=function ").append("(");
        if(params!=null && params.length>0){
            for(int i=0;i<params.length;i++){
                jsScript.append(" var").append(i)
                        .append(",");
            }
        }
        int id = (int)(Math.random()*1000);
        jsScript.append("call){")
                .append("var id = ")
                .append(generateFuncId)
                .append("();")
                .append("var compId='").append(objName).append("-").append(m.getName()).append("Complete").append("'+id;")
                .append(wCache)
                .append("[compId]=call;");
        if(params!=null && params.length>0){
            jsScript.append("var args=[];")
                    .append("for(var i=0;i<").append(params.length).append(";i++){")
                    .append("args[i]=arguments[i];")
                    .append("}");
        }
        jsScript.append(exector)
                .append(".exec(")
                .append("'")
                .append(objName)
                .append("','")
                .append(m.getName())
                .append("',");
        if(params == null || params.length == 0){
            jsScript.append("null");
        }else{
            jsScript.append("JSON.stringify(args)");
        }
        jsScript.append(",compId);return compId;");
        jsScript.append("};");
        return jsScript.toString();
    }

    /**
     * 生成js代理java全局调用的方法以及初始化方法
     * @return
     */
    public static final String generateSyncExecProxyMethod(){
        StringBuilder jsScript = new StringBuilder();
        jsScript.append("(function(){")
                .append("window['").append(wCache).append("']||(window['").append(wCache).append("']={});")
                .append("window['").append(completeCall).append("']||(window['").append(completeCall).append("']=function(id,state,val){if(").append(wCache).append("[id]){try{val=val==null?null:JSON.parse(val);}catch(e){try{logger.error('json转换出错，{}',[val]);}catch(e){}}").append(wCache).append("[id](state,val);}delete ").append(wCache).append("[id];});")
                .append("window['").append(methodCount).append("']||(window['").append(methodCount).append("']=1);")
                .append("window['").append(generateFuncId).append("']||(window['").append(generateFuncId).append("']=function(pref){pref=pref||'';var id=pref+(window['").append(methodCount).append("']++);if(window['").append(methodCount).append("']>10000){window['").append(methodCount).append("']=1;}return ").append(wCache).append("[id]?window['").append(generateFuncId).append("'](pref):id;});")
                .append("window['").append(proxyJsExtorMethodName).append("']||(window['").append(proxyJsExtorMethodName).append("']=function(){var args;if(arguments.length>1){args=[];for(var i=1;i<arguments.length;i++){var arg=arguments[i];if(arg==null)args[i-1]=arg;else args[i-1]=JSON.parse(arg);}}var mName=arguments[0];var result=!window[mName]||window[mName].apply(window,args);if(result!=null) return JSON.stringify(result);});")
                .append("})();");
        return jsScript.toString();
    }

    /**
     * 生成一个java调用js方法的模版js
     * @param params
     * @param jsMethodName
     * @return
     */
    public static String getExecJson(Object[] params,String jsMethodName){
        String paramJsons[] = null;
        if(params != null){
            paramJsons = new String[params.length];
            for(int i=0;i<params.length;i++){
                if(params[i]!=null){
                    paramJsons[i] = JsonHandler.toJson(params[i]);
                }else{
                    paramJsons[i]=null;
                }
            }
        }
        StringBuilder builder = new StringBuilder(proxyJsExtorMethodName)
                .append("('")
                .append(jsMethodName)
                .append("'");
        if(paramJsons != null){
            for(String json:paramJsons){
                builder.append(",");
                if(json==null) builder.append("undefined");
                else builder.append("'").append(json).append("'");
            }
        }
        builder.append(")");
        String jsCode = builder.toString();
        return jsCode;
    }

    /**
     * 异步方法回调执行
     * @param webEngine
     * @param id
     * @param state
     * @param val
     */
    public static final void execCompleteFunc(WebEngine webEngine,String id,int state,Object val){
        StringBuilder execJs = new StringBuilder();
        execJs.append("window['")
                .append(completeCall)
                .append("']('")
                .append(id)
                .append("',")
                .append(state);
        if(val==null){
            execJs.append(");");
        }else{
            String jsonVal = JsonHandler.toJson(val);
            execJs.append(",")
                    .append(jsonVal)
                    .append(");");
        }
        Platform.runLater(()->{
            webEngine.executeScript(execJs.toString());
        });
    }

}
